﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IEC
{
    public class ModList
    {
        private bool dontUpdate = false;
        public ModList() { }

        public ModList(ModList other)
        {
            dontUpdate = true;
            foreach(var item in other.List)
            {
                items.AddLast(new ModListItem(item));
            }
        }

        LinkedList<ModListItem> items = new LinkedList<ModListItem>();

        public void UpdateList()
        {
            if (dontUpdate)
            {
                Debug.Fail("Cant update the list");
            }
            if(MainWindow.config.GetStatus() == GameConfig.ConfigStatus.OK)
            {
                items.Clear();
                var dir = new System.IO.DirectoryInfo(MainWindow.config.GetModPath());
                if (dir.Exists)
                {
                    foreach(var d in dir.GetDirectories())
                    {
                        items.AddLast(new ModListItem(d));
                    }
                }
            }
        }
        public HashSet<string> CheckWorkshopNotSync()
        {
            var folder = MainWindow.config.GetModWorkshopPath();
            if (folder == null)
                return new HashSet<string>();
            var folderObj = new System.IO.DirectoryInfo(folder);
            if (!folderObj.Exists)
                return new HashSet<string>();

            HashSet<string> already_has_ids = new HashSet<string>();

            HashSet<string> retNames = new HashSet<string>();

            foreach (var item in items)
            {
                if (item.id != null && item.metaName != null)
                {
                    already_has_ids.Add(item.id);
                    if (item.notSync)
                        retNames.Add(item.metaName);
                }
            }

            foreach(var subfolder in folderObj.EnumerateDirectories())
            {
                var metapath = new System.IO.FileInfo(System.IO.Path.Combine(subfolder.FullName, "metadata.xml"));
                if (!metapath.Exists)
                    continue;
                try
                {
                    using(var fstream = metapath.OpenRead())
                    using (var xmlReader = System.Xml.XmlReader.Create(fstream))
                    {
                        string mMetaname, mId, mVersion;
                        ModListItem.ParseMetadata(xmlReader, out mMetaname, out mId, out mVersion);
                        if (!already_has_ids.Contains(mId))
                        {
                            //new mod
                            retNames.Add(mMetaname ?? "<名称未识别>");
                        }
                    }
                }
                catch (Exception)
                {

                }

            }

            return retNames;
        }
        public string SaveLists()
        {
            if(MainWindow.config.GetStatus() == GameConfig.ConfigStatus.OK)
            {
                StringBuilder output = new StringBuilder();
                foreach(var item in items)
                {
                    var r = item.SaveChanges(MainWindow.config);
                    if (r != null)
                        output.Append(r).AppendLine();
                }
                if(output.Length == 0)
                {
                    output.Append("未修改任何状态");
                }
                return output.ToString();
            }
            return "配置文件不可用";
        }

        public LinkedList<ModListItem> List { get { return items; } }
    }

    public class ModListItem
    {
        public string folderName;
        public string metaName;
        public bool Disabled;
        public bool NeedUpdate;
        public string id;
        public string version;
        public bool notSync;
        public ModListItem() { }
        public ModListItem(ModListItem other)
        {
            this.folderName = other.folderName;
            this.metaName = other.metaName;
            this.Disabled = other.Disabled;
            this.NeedUpdate = other.NeedUpdate;
            this.id = other.id;
            this.version = other.version;
            this.notSync = other.notSync;
        }

        public string SaveChanges(GameConfig config)
        {
            if(!new System.IO.DirectoryInfo(System.IO.Path.Combine(config.GetModPath(), folderName)).Exists)
            {
                return "不存在Mod " + (metaName ?? folderName);
            }
            var disable = new System.IO.FileInfo(System.IO.Path.Combine(config.GetModPath(), folderName, "disable.it"));
            if(disable.Exists != Disabled)
            {
                if (Disabled)
                {
                    disable.Create().Close();
                    return "已关闭" + (metaName ?? folderName);
                }
                else
                {
                    disable.Delete();
                    return "已开启" + (metaName ?? folderName);
                }
            }
            return null;

        }

        public static void ParseMetadata(System.Xml.XmlReader xmlReader, out string metaName, out string id, out string version)
        {
            LinkedList<string> xmlPos = new LinkedList<string>();
            metaName = null;
            id = null;
            version = null;
            while (xmlReader.Read())
            {
                switch (xmlReader.NodeType)
                {
                    case System.Xml.XmlNodeType.Element:
                        xmlPos.AddLast(xmlReader.Name);
                        if (xmlPos.Count > 50) // impossible
                            break;
                        break;
                    case System.Xml.XmlNodeType.EndElement:
                        if (xmlPos.Last.Value == xmlReader.Name)
                            xmlPos.RemoveLast();
                        break;
                    case System.Xml.XmlNodeType.Text:
                        if (xmlPos.Count == 2 && xmlPos.First.Value == "metadata" && xmlPos.Last.Value == "name")
                        {
                            metaName = xmlReader.Value;
                        }
                        if (xmlPos.Count == 2 && xmlPos.First.Value == "metadata" && xmlPos.Last.Value == "id")
                        {
                            id = xmlReader.Value;
                        }
                        if (xmlPos.Count == 2 && xmlPos.First.Value == "metadata" && xmlPos.Last.Value == "version")
                        {
                            version = xmlReader.Value;
                        }
                        break;
                }
            }
        }

        public ModListItem(System.IO.DirectoryInfo folder)
        {
            folderName = folder.Name;
            Disabled = false;
            NeedUpdate = false;
            metaName = null;
            id = null;
            version = null;
            foreach(var file in folder.GetFiles())
            {
                if (file.Name == "disable.it")
                    Disabled = true;
                if (file.Name == "update.it")
                    NeedUpdate = true;
                if(file.Name == "metadata.xml")
                {
                    using (var fstream = file.OpenRead())
                    using (var xmlReader = System.Xml.XmlReader.Create(fstream))
                    {
                        ParseMetadata(xmlReader, out metaName, out id, out version);
                    }
                }
            }

            notSync = false;
            try
            {
                if(id != null)
                {
                    string workshopFolder = MainWindow.config.GetModWorkshopPath();
                    if(workshopFolder != null)
                    {
                        string wMetaName, wId, wVersion;
                        System.IO.FileInfo file = new System.IO.FileInfo(System.IO.Path.Combine(workshopFolder, id, "metadata.xml"));
                        if (file.Exists)
                        {
                            using (var fstream = file.OpenRead())
                            using (var xmlReader = System.Xml.XmlReader.Create(fstream))
                            {
                                ParseMetadata(xmlReader, out wMetaName, out wId, out wVersion);
                            }
                            if(wId == id && wVersion != version)
                            {
                                notSync = true;
                            }
                        }
                        else
                        {
                            notSync = true;
                        }
                    }
                }
            }
            catch (Exception)
            {

            }
        }
    }
}
